home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / smail-3.1.28 / src / retry.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-20  |  21.0 KB  |  1,041 lines

  1. /* @(#)src/retry.c    1.21 9/20/92 18:46:27 */
  2.  
  3. /*
  4.  * retry.c:
  5.  *      Control how often addresses are retried, and how long
  6.  *      retries are attempted until Smail gives up.
  7.  *
  8.  *    This file was contributed by Chip Salzenberg <chip@tct.com>.
  9.  *    It has been modified.
  10.  *
  11.  *    external functions: read_retry_file, retry_addr_before,
  12.  *                retry_addr_after, retry_addr_finished,
  13.  *                retry_host_lock, retry_host_unlock
  14.  */
  15.  
  16. #include <stdio.h>
  17. #include <sys/types.h>
  18. #include <sys/stat.h>
  19. #include <signal.h>
  20. #include <ctype.h>
  21. #include <errno.h>
  22. #include "defs.h"
  23. #include "smail.h"
  24. #include "addr.h"
  25. #include "transport.h"
  26. #include "log.h"
  27. #include "parse.h"
  28. #include "dys.h"
  29. #include "lookup.h"
  30. #include "jump.h"
  31. #ifndef DEPEND
  32. # include "extern.h"
  33. # include "debug.h"
  34. # include "error.h"
  35. #endif
  36.  
  37. #if defined(UNIX_SYS5) || defined(POSIX_OS) || defined(USE_FCNTL)
  38. # include <fcntl.h>
  39. #else
  40. # if defined(UNIX_BSD)
  41. #  include <sys/file.h>
  42. # endif
  43. #endif
  44.  
  45. /*
  46.  * the retry mechanism requires three-parameter open() and
  47.  * kernel locking.  if either of these features is missing,
  48.  * then all retry features are stubbed out.
  49.  */
  50.  
  51. #if defined(O_CREAT) && defined(lock_fd_wait)
  52.  
  53. #define RETRY_MODE   0644        /* file creation modes */
  54.  
  55. #ifdef O_SYNC
  56. # define O_SWYM O_SYNC
  57. #else
  58. # define O_SWYM 0
  59. #endif
  60.  
  61. #ifdef ANSI_C
  62. # define P_(x)  x
  63. # define VOLATILE volatile
  64. #else
  65. # define P_(x)  ()
  66. # define VOLATILE /**/
  67. #endif
  68.  
  69. struct retry {
  70.     struct retry *succ;            /* next in chain */
  71.     char    *domains;            /* target domain, or "*" */
  72.     time_t  interval;            /* minimum time between tries */
  73.     time_t  duration;            /* how long to keep trying */
  74. };
  75.  
  76. static struct retry *retries = NULL;    /* array of control structures */
  77.  
  78. static int locked_fd = -1;
  79. static char *locked_path = NULL;
  80. static struct retry *locked_retry = NULL;
  81. static JUMP_ENVBUF tryfile_jmp;
  82.  
  83. static struct retry *default_retry P_((void));
  84. static int match_retry_domain P_((char *, char *));
  85. static int allow_now P_((int, char *, time_t, time_t, struct retry *,
  86.              struct error **));
  87. static int allow_later P_((time_t, time_t, struct retry *, struct error **));
  88. static char *tryfile_name P_((struct transport *, char *, int));
  89. static int tryfile_cat P_((struct str *, char *, unsigned, int, int, int));
  90. static int tryfile_mkdir P_((struct str *));
  91. static int tryfile_lock P_((int, long));
  92. static void tryfile_unlock P_((int));
  93. static void tryfile_alarm P_((int));
  94. static void write_error P_((int, char *, struct error *));
  95. static void read_error P_((int, char *, struct error *));
  96.  
  97. /*
  98.  * read_retry_file - read and remember contents of retry file
  99.  */
  100.  
  101. char *
  102. read_retry_file()
  103. {
  104.     struct stat statbuf;
  105.     struct retry *r, *nr;
  106.     FILE *f;
  107.     char *entry, *error;
  108.  
  109.     /*
  110.      * forget any previously-read retry data
  111.      */
  112.     for (r = retries; r; r = nr) {
  113.     nr = r->succ;
  114.     xfree(r->domains);
  115.     xfree((char *)r);
  116.     }
  117.     retries = NULL;
  118.  
  119.     /*
  120.      * try to open retry file, stat file if possible
  121.      */
  122.     if (retry_file == NULL || EQ(retry_file, "-")) {
  123.     return NULL;
  124.     }
  125.     f = fopen(retry_file, "r");
  126.     if (f == NULL) {
  127.     if (require_configs) {
  128.         return xprintf("cannot open %s: %s", retry_file, strerrno());
  129.     }
  130.  
  131.     add_config_stat(retry_file, (struct stat *)NULL);
  132.     retries = default_retry();
  133.     return NULL;
  134.     }
  135.  
  136.     (void)fstat(fileno(f), &statbuf);
  137.     add_config_stat(retry_file, &statbuf);
  138.  
  139.     /*
  140.      * loop and read all of the table entries in the retry file
  141.      */
  142.     error = NULL;
  143.     nr = NULL;
  144.     while (entry = read_entry(f)) {
  145.     struct attribute *new;
  146.     char *name, *value, *p;
  147.     time_t interval, duration;
  148.     long n;
  149.  
  150.     new = parse_table(entry, &error);
  151.     if (new == NULL) {
  152.         break;
  153.     }
  154.     name = new->name;
  155.     value = new->value;
  156.     xfree((char *)new);
  157.  
  158.     /* parse duration first, since it appears second */
  159.     duration = 0;
  160.     p = index(value, '/');
  161.     if (p) {
  162.         *p++ = '\0';
  163.         n = ivaltol(p);
  164.         if (n < 0) {
  165.         error = xprintf("invalid retry interval: %s", p);
  166.         xfree(name);
  167.         break;
  168.         }
  169.         duration = n;
  170.     }
  171.  
  172.     /* parse interval */
  173.     interval = 0;
  174.     if (*value) {
  175.         n = ivaltol(value);
  176.         if (n < 0) {
  177.         error = xprintf("invalid retry duration: %s", value);
  178.         xfree(name);
  179.         break;
  180.         }
  181.         interval = n;
  182.     }
  183.  
  184.     /* allocate new structure */
  185.     r = (struct retry *) xmalloc(sizeof(struct retry));
  186.  
  187.     /* assign new structure's domain */
  188.     r->domains = COPY_STRING(name);
  189.  
  190.     /* assign new structure's limits */
  191.     r->interval = interval;
  192.     r->duration = duration;
  193.  
  194.     /* append new structure to chain */
  195.     r->succ = NULL;
  196.     if (nr == NULL) {
  197.         retries = r;
  198.     } else {
  199.         nr->succ = r;
  200.     }
  201.     nr = r;
  202.  
  203.     /* free string returned by parse_table */
  204.     xfree(name);
  205.  
  206.     /* wildcard obviates need to read further */
  207.     if (EQ(name, "*")) {
  208.         break;
  209.     }
  210.     }
  211.     (void) fclose(f);
  212.  
  213.     /*
  214.      * if no errors, and there is no default record, and if
  215.      * global configuration requires a default record, add it.
  216.      */
  217.     if ((nr == NULL || !EQ(nr->domains, "*"))
  218.     && (r = default_retry()) != NULL)
  219.     {
  220.     if (nr == NULL) {
  221.         retries = r;
  222.     } else {
  223.         nr->succ = r;
  224.     }
  225.     }
  226.  
  227.     /* return error message, or NULL for success */
  228.     return error;
  229. }
  230.  
  231. /*
  232.  * default_retry - build default retry record from global configuration
  233.  */
  234. static struct retry *
  235. default_retry()
  236. {
  237.     struct retry *r;
  238.  
  239.     if (!retry_interval && !retry_duration) {
  240.     return NULL;
  241.     }
  242.  
  243.     r = (struct retry *) xmalloc(sizeof(struct retry));
  244.     r->domains = COPY_STRING("*");
  245.     r->interval = retry_interval;
  246.     r->duration = retry_duration;
  247.     return r;
  248. }
  249.  
  250. /*
  251.  * retry_addr_before - retry processing before transport attempt
  252.  */
  253. struct addr *
  254. retry_addr_before(in, defer, fail)
  255.     struct addr *in;
  256.     struct addr **defer;
  257.     struct addr **fail;
  258. {
  259.     time_t spooled = message_date();
  260.     struct addr *out, *cur, *next;
  261.  
  262.     out = NULL;
  263.     for (cur = in; cur; cur = next) {
  264.     struct addr **where = &out;
  265.     struct retry *r;
  266.  
  267.     next = cur->succ;
  268.  
  269.     /* skip if no next host */
  270.     if (cur->next_host == NULL) {
  271.         cur->succ = out;
  272.         out = cur;
  273.         continue;
  274.     }
  275.  
  276.     for (r = retries; r; r = r->succ) {
  277.         if (match_retry_domain(r->domains, cur->next_host)) {
  278.         char *tryname;
  279.         int may_deliver, fd;
  280.         time_t started;
  281.  
  282.         /* calculate path of retry file */
  283.         if ((tryname = tryfile_name(cur->transport,
  284.                         cur->next_host, FALSE)) == NULL)
  285.         {
  286.             break;
  287.         }
  288.  
  289.         DEBUG1(DBG_RETRY_LO, "examine %s\n", tryname);
  290.  
  291.         /* examine the retry file: lock; ignore empties */
  292.         for (;;) {
  293.             int lk;
  294.  
  295.             if ((fd = open(tryname, O_RDWR|O_SWYM)) == -1) {
  296.             time(&started);
  297.             may_deliver = TRUE;
  298.             break;
  299.             }
  300.             lk = tryfile_lock(fd, 0L);
  301.             if (lk == DB_AGAIN) {
  302.             (void) close(fd);
  303.             continue;
  304.             }
  305.  
  306.             /* the rest happens only once */
  307.             if (lk == DB_SUCCEED) {
  308.             time(&started);
  309.             may_deliver = allow_now(fd, tryname, spooled, started,
  310.                         r, &cur->error);
  311.             (void) tryfile_unlock(fd);
  312.             }
  313.             (void) close(fd);
  314.             break;
  315.         }
  316.  
  317.         if (may_deliver) {
  318.             /* try it; if it fails, we'll touch the retry file */
  319.             cur->flags |= ADDR_RETRY_FILE;
  320.         } else {
  321.             /* retry interval has not yet expired */
  322.             where = allow_later(spooled, started, r, &cur->error)
  323.                 ? defer : fail;
  324.         }
  325.  
  326.         /* stop looking for retry specs after first match */
  327.         break;
  328.         }
  329.     }
  330.  
  331.     cur->succ = *where;
  332.     *where = cur;
  333.     }
  334.  
  335.     return out;
  336. }
  337.  
  338. /*
  339.  * retry_addr_after - retry processing after delivery attempt,
  340.  *              possibly failing addresses deferred by transport
  341.  */
  342. struct addr *
  343. retry_addr_after(started, in, fail)
  344.     time_t started;
  345.     struct addr *in;
  346.     struct addr **fail;
  347. {
  348.     time_t spooled = message_date();
  349.     struct addr *out, *cur, *next;
  350.  
  351.     out = NULL;
  352.     for (cur = in; cur; cur = next) {
  353.     struct addr **where = &out;
  354.     struct retry *r;
  355.  
  356.     next = cur->succ;
  357.  
  358.     if (cur->flags & ADDR_RETRY_FILE) {
  359.         for (r = retries; r; r = r->succ) {
  360.         if (match_retry_domain(r->domains, cur->next_host)) {
  361.  
  362.             /* if total retry duration exceeded, fail address */
  363.             if (! allow_later(spooled, started, r, &cur->error)) {
  364.             where = fail;
  365.             }
  366.  
  367.             /* stop looking for retry specs after first match */
  368.             break;
  369.         }
  370.         }
  371.     }
  372.  
  373.     cur->succ = *where;
  374.     *where = cur;
  375.     }
  376.  
  377.     return out;
  378. }
  379.  
  380. /*
  381.  * retry_addr_finished - record success or failure
  382.  */
  383. void
  384. retry_addr_finished(addr)
  385.     struct addr *addr;
  386. {
  387.     char *prev_host = NULL;
  388.     struct addr *cur;
  389.  
  390.     for (cur = addr; cur; cur = cur->succ) {
  391.     if (cur->flags & ADDR_RETRY_FILE) {
  392.         struct error *error = cur->error;
  393.         char *tryname;
  394.         int fd;
  395.  
  396.         /* don't bother writing to the same file twice in a row */
  397.         if (prev_host && EQIC(prev_host, cur->next_host)) {
  398.         continue;
  399.         }
  400.         prev_host = cur->next_host;
  401.  
  402.         /* calculate path of retry file */
  403.         if ((tryname = tryfile_name(cur->transport, cur->next_host,
  404.                     (error != NULL))) == NULL)
  405.         {
  406.         continue;
  407.         }
  408.  
  409.         DEBUG2(DBG_RETRY_LO, "%s error message in %s\n",
  410.            error ? "writing" : "removing", tryname);
  411.  
  412.         /* write to, or remove, retry file */
  413.         for (;;) {
  414.         int lk;
  415.  
  416.         if ((fd = open(tryname, O_WRONLY | (error ? O_CREAT : 0),
  417.                    RETRY_MODE)) == -1)
  418.         {
  419.             break;
  420.         }
  421.         lk = tryfile_lock(fd, 0L);
  422.         if (lk == DB_AGAIN) {
  423.             (void) close(fd);
  424.             continue;
  425.         }
  426.  
  427.         /* the rest happens only once */
  428.         if (lk == DB_SUCCEED) {
  429.             write_error(fd, tryname, error);
  430.             tryfile_unlock(fd);
  431.         }
  432.         (void) close(fd);
  433.         break;
  434.         }
  435.     }
  436.     }
  437. }
  438.  
  439. /*
  440.  * retry_host_lock - lock the target host for delivery the given addresses
  441.  *
  442.  * return SUCCEED if lock succeeded, FAIL if it failed.
  443.  * if failure is temporary, set *defer_failure.
  444.  *
  445.  * some transports will use this function.  those that do so won't
  446.  * call retry_addr_before(), so retry_addr_*() will do nothing.
  447.  */
  448. int
  449. retry_host_lock(transport, host, defer_failure, error)
  450.     struct transport *transport;
  451.     char *host;
  452.     int *defer_failure;
  453.     struct error **error;
  454. {
  455.     time_t spooled = message_date();
  456.     time_t started;
  457.     struct retry *r;
  458.     char *tryname;
  459.     int fd, dfok, ret;
  460.  
  461.     /* safety: unlock previously locked retry file */
  462.     if (locked_fd >= 0) {
  463.     tryfile_unlock(locked_fd);
  464.     (void) close(locked_fd);
  465.     locked_fd = -1;
  466.     }
  467.     if (locked_path) {
  468.     xfree(locked_path);
  469.     locked_path = NULL;
  470.     }
  471.  
  472.     /* calculate path of retry file, creating directories */
  473.     if ((tryname = tryfile_name(transport, host, TRUE)) == NULL) {
  474.     return FAIL;
  475.     }
  476.  
  477.     DEBUG1(DBG_RETRY_LO, "lock %s\n", tryname);
  478.  
  479.     /* open and lock retry file */
  480.     for (;;) {
  481.     int lk;
  482.  
  483.     if ((fd = open(tryname, O_RDWR|O_CREAT|O_SWYM, RETRY_MODE)) == -1) {
  484.         return FAIL;
  485.     }
  486.     lk = tryfile_lock(fd, host_lock_timeout);
  487.     if (lk == DB_SUCCEED) {
  488.         break;
  489.     }
  490.     if (lk == DB_AGAIN) {
  491.         (void) close(fd);
  492.         continue;
  493.     }
  494.  
  495.     DEBUG1(DBG_RETRY_LO, "lock %s TIMED OUT\n", tryname);
  496.     (void) close(fd);
  497.     if (*error == NULL) {
  498.         *error = note_error(ERR_175, "host retry file locked");
  499.     }
  500.     *defer_failure = TRUE;
  501.     return FAIL;
  502.     }
  503.  
  504.     /* now is the official start of attempt */
  505.     time(&started);
  506.  
  507.     /* assume the best */
  508.     ret = SUCCEED;
  509.     dfok = TRUE;
  510.  
  511.     /* if host has retry parameters, enforce them */
  512.     for (r = retries; r; r = r->succ) {
  513.     if (match_retry_domain(r->domains, host)) {
  514.  
  515.         /* notice if it's too soon to try delivery */
  516.         ret = allow_now(fd, tryname, spooled, started, r, error)
  517.           ? SUCCEED : FAIL;
  518.  
  519.         /* we can defer if further retries would be soon enough */
  520.         dfok = allow_later(spooled, started, r, error);
  521.  
  522.         /* stop looking for retry specs after first match */
  523.         break;
  524.     }
  525.     }
  526.  
  527.     /* keep human informed */
  528.     DEBUG3(DBG_RETRY_LO, "lock %s (%s) %s\n",
  529.        (ret == SUCCEED) ? "succeeded" : "failed",
  530.        dfok ? "will defer failure" : "will not defer failure",
  531.        tryname);
  532.  
  533.     /* if retry control allows deferral, inform caller */
  534.     if (dfok) {
  535.     *defer_failure = TRUE;
  536.     }
  537.  
  538.     if (ret == SUCCEED) {
  539.     /* remember name, fd and retry parameters */
  540.     locked_fd = fd;
  541.     locked_path = COPY_STRING(tryname);
  542.     locked_retry = r;
  543.     } else {
  544.     /* we won't be needing the lock file after all */
  545.     tryfile_unlock(fd);
  546.     (void) close(fd);
  547.     }
  548.  
  549.     return ret;
  550. }
  551.  
  552. /*
  553.  * retry_host_unlock - unlock the target host for delivery, recording status
  554.  *
  555.  * set *fail if retry time has expired.
  556.  *
  557.  * some transports will use this function.  those that do so won't
  558.  * call retry_addr_before(), so retry_addr_*() will do nothing.
  559.  */
  560. void
  561. retry_host_unlock(started, error)
  562.     time_t started;
  563.     struct error *error;
  564. {
  565.     time_t spooled = message_date();
  566.  
  567.     if (locked_fd < 0) {
  568.     return;
  569.     }
  570.  
  571.     DEBUG2(DBG_RETRY_LO, "unlock (%s) %s\n",
  572.        error ? "error" : "success", locked_path);
  573.  
  574.     /* write the error */
  575.     write_error(locked_fd, locked_path, error);
  576.  
  577.     /* unlock and close the retry file */
  578.     tryfile_unlock(locked_fd);
  579.     (void) close(locked_fd);
  580.  
  581.     /* forget that we ever saw the lock file */
  582.     locked_fd = -1;
  583.     xfree(locked_path);
  584.     locked_path = NULL;
  585.     locked_retry = NULL;
  586. }
  587.  
  588. /*
  589.  * match_retry_domain - determine if domain pattern matches given host
  590.  */
  591. static int
  592. match_retry_domain(domains, target)
  593.     char *domains;            /* colon separated list of domains */
  594.     char *target;            /* target to test against */
  595. {
  596.     register char *cur;            /* current domain being checked */
  597.  
  598.     if (EQ(domains, "*")) {
  599.     return TRUE;
  600.     }
  601.  
  602.     for (cur = strcolon(domains); cur; cur = strcolon((char *)NULL)) {
  603.     if (is_suffix(cur, target, FALSE)) {
  604.         return TRUE;
  605.     }
  606.     }
  607.  
  608.     return FALSE;
  609. }
  610.  
  611. /*
  612.  * allow_now - can we deliver now?  and if failure, can we defer?
  613.  */
  614. static int
  615. allow_now(fd, tryname, spooled, started, r, error)
  616.     int fd;
  617.     char *tryname;
  618.     time_t spooled, started;
  619.     struct retry *r;
  620.     struct error **error;
  621. {
  622.     struct stat statbuf;
  623.     time_t last;
  624.  
  625.     last = 0;
  626.     if (fstat(fd, &statbuf) == 0 && statbuf.st_size) {
  627.     last = statbuf.st_mtime;
  628.     }
  629.  
  630.     if (last && last <= started && (started - last) < r->interval) {
  631.  
  632.     /* retry interval has not passes, so we won't deliver */
  633.  
  634.     if ((started - spooled) > r->duration) {
  635.         /* your time is up */
  636.         if (*error == NULL) {
  637.         struct error err;
  638.  
  639.         read_error(fd, tryname, &err);
  640.         *error = note_error(ERR_NSOWNER | err.info, err.message);
  641.         }
  642.     } else {
  643.         /* just wait a little longer */
  644.         if (*error == NULL) {
  645.         *error = note_error(ERR_DONTLOG | ERR_174,
  646.                     "retry interval not reached");
  647.         }
  648.     }
  649.     return FALSE;
  650.     }
  651.  
  652.     return TRUE;
  653. }
  654.  
  655. /*
  656.  * allow_later - can we make more retries after this one?
  657.  */
  658. static int
  659. allow_later(spooled, started, r, error)
  660.     time_t spooled, started;
  661.     struct retry *r;
  662.     struct error **error;
  663. {
  664.     /* if this was the last try... */
  665.     if ((started - spooled) > r->duration) {
  666.     if (*error == NULL) {
  667.         *error = note_error(ERR_173, "retry duration exceeded");
  668.     }
  669.     return FALSE;
  670.     }
  671.  
  672.     /* there is still time for more retries */
  673.     return TRUE;
  674. }
  675.  
  676. /*
  677.  * tryfile_name - figure name of file used to hold timestamp for
  678.  *          the given host.
  679.  *
  680.  * Note: returns address of static area.
  681.  */
  682. static char *
  683. tryfile_name(transport, host, create_dirs)
  684.     struct transport *transport;
  685.     char *host;
  686.     int create_dirs;
  687. {
  688.     static size_t pathmax = 0;
  689.     static struct str path;
  690.     static int inited = FALSE;
  691.  
  692. #ifdef POSIX_OS
  693.     if (pathmax == 0) {
  694.     long n = pathconf(".", _PC_NAME_MAX);
  695.     if (n != -1) {
  696.         pathmax = n;
  697.     }
  698.     }
  699. #else
  700. #ifdef UNIX_BSD
  701.     if (pathmax == 0) {
  702.     pathmax = 250;
  703.     }
  704. #endif /* UNIX_BSD */
  705. #endif /* POSIX_OS */
  706.     if (pathmax == 0) {
  707.     pathmax = 14;
  708.     }
  709.  
  710.     if (!inited) {
  711.     STR_INIT(&path);
  712.     inited = TRUE;
  713.     }
  714.     path.i = 0;
  715.  
  716.     str_cat(&path, "retry");
  717.     if (create_dirs && tryfile_mkdir(&path) == FAIL) {
  718.     return NULL;
  719.     }
  720.  
  721.     STR_NEXT(&path, '/');
  722.     str_cat(&path, (transport->retry_dir && transport->retry_dir[0])
  723.            ? transport->retry_dir : transport->name);
  724.     if (create_dirs && tryfile_mkdir(&path) == FAIL) {
  725.     return NULL;
  726.     }
  727.  
  728.     if (strlen(host) <= pathmax) {
  729.     if (tryfile_cat(&path, host, strlen(host), TRUE, FALSE,
  730.             create_dirs) == FAIL)
  731.     {
  732.         return NULL;
  733.     }
  734.     } else {
  735.     char *p, *q;
  736.     int first, partial;
  737.  
  738.     first = TRUE;
  739.     p = host + strlen(host);
  740.     for (;;) {
  741.         while (p > host && *(p - 1) == '.') {
  742.         --p;
  743.         }
  744.         if (p == host) {
  745.         break;
  746.         }
  747.         q = p;
  748.         partial = FALSE;
  749.         while (p > host && *(p - 1) != '.') {
  750.         if ((q - p) >= (pathmax - 1)) {
  751.             partial = TRUE;
  752.             break;
  753.         }
  754.         --p;
  755.         }
  756.         if (tryfile_cat(&path, p, (q - p), first, partial,
  757.                 create_dirs) == FAIL)
  758.         {
  759.         return NULL;
  760.         }
  761.         first = FALSE;
  762.     }
  763.     }
  764.     STR_NEXT(&path, '\0');
  765.     return path.p;
  766. }
  767.  
  768. static int
  769. tryfile_cat(sp, p, len, first, partial, create_dirs)
  770.     struct str *sp;
  771.     char *p;
  772.     unsigned len;
  773.     int first, partial, create_dirs;
  774. {
  775.     unsigned i;
  776.  
  777.     if (!first && sp->i && sp->p[sp->i - 1] != '_') {
  778.     STR_NEXT(sp, '.');
  779.     }
  780.  
  781.     if (create_dirs && tryfile_mkdir(sp) == FAIL) {
  782.     return FAIL;
  783.     }
  784.  
  785.     STR_NEXT(sp, '/');
  786.     for (i = 0; i < len; ++i) {
  787.     int c = *(p + i) & 0xFF;
  788.     if (isupper(c)) {
  789.         c = tolower(c);
  790.     }
  791.     STR_NEXT(sp, c);
  792.     }
  793.     if (partial) {
  794.     STR_NEXT(sp, '_');
  795.     }
  796.  
  797.     return SUCCEED;
  798. }
  799.  
  800. static int
  801. tryfile_mkdir(sp)
  802.     struct str *sp;
  803. {
  804.     struct stat statbuf;
  805.     int ret = SUCCEED;
  806.  
  807.     STR_NEXT(sp, '\0');
  808.     if (stat(sp->p, &statbuf) == -1) {
  809.     DEBUG1(DBG_RETRY_LO, "make directory %s\n", sp->p);
  810.     (void) mkdir(sp->p, auto_mkdir_mode);
  811.     if (stat(sp->p, &statbuf) == -1) {
  812.         write_log(LOG_SYS, "can't create directory %s", sp->p);
  813.         ret = FAIL;
  814.     }
  815.     }
  816.     sp->i--;
  817.  
  818.     return ret;
  819. }
  820.  
  821. /*
  822.  * tryfile_lock - lock an open retry file; optionally, time out
  823.  *
  824.  * Returns DB_SUCCESS (good), DB_FAIL (bad),
  825.  * or DB_AGAIN (if file was removed).
  826.  */
  827. static int
  828. tryfile_lock(fd, timeout)
  829.     int fd;
  830.     long timeout;
  831. {
  832.     VOLATILE JUMPSIG old_sigalrm;
  833.     VOLATILE int old_alarm;
  834.     int ret;
  835.  
  836.     if (timeout && JUMP_SETJMP(tryfile_jmp)) {
  837.     ret = DB_FAIL;
  838.     } else {
  839.     /* lock retry file with optional timeout */
  840.     if (timeout) {
  841.         old_alarm = alarm(0);
  842.         JUMP_SETSIG(SIGALRM, tryfile_alarm, &old_sigalrm);
  843.         (void) alarm(timeout < 2 ? 2 : (unsigned)timeout);
  844.     }
  845.  
  846.     if (lock_fd_wait(fd) == FAIL) {
  847.         ret = DB_FAIL;
  848.     } else {
  849.         struct stat st;
  850.  
  851.         ret = (fstat(fd, &st) == 0 && st.st_nlink > 0)
  852.            ? DB_SUCCEED : DB_AGAIN;
  853.     }
  854.     if (timeout) {
  855.         (void) alarm(0);
  856.         JUMP_CLEARSIG(SIGALRM, &old_sigalrm);
  857.         if (old_alarm) {
  858.         (void) alarm(old_alarm);
  859.         }
  860.     }
  861.     }
  862.  
  863.     return ret;
  864. }
  865.  
  866. /*
  867.  * tryfile_unlock - unlock a retry file locked with timeout
  868.  */
  869. static void
  870. tryfile_unlock(fd)
  871.     int fd;
  872. {
  873.     unlock_fd_wait(fd);
  874. }
  875.  
  876. /*
  877.  * tryfile_alarm - alarm function
  878.  */
  879. static void
  880. tryfile_alarm(sig)
  881.      int sig;
  882. {
  883.     JUMP_LONGJMP(tryfile_jmp, 1);
  884. }
  885.  
  886. /*
  887.  * write_error - write an error description to a retry file, or remove it
  888.  */
  889. static void
  890. write_error(fd, tryfile, error)
  891.     int fd;
  892.     char *tryfile;
  893.     struct error *error;
  894. {
  895.     if (error == NULL) {
  896.     /* no error: remove file */
  897.     (void) unlink(tryfile);
  898.     } else {
  899.     char *e;
  900.     size_t elen;
  901.  
  902.     /* write error code and message */
  903.     e = xprintf("%ld %s\n", error->info & ERR_MASK, error->message);
  904.     elen = strlen(e);
  905.     (void) lseek(fd, 0L, 0);
  906.     (void) write(fd, e, elen + 1);
  907.     (void) xfree(e);
  908.  
  909.     /* eliminate remaining bytes, to avoid confusing human readers */
  910.     (void) fsetsize(fd, (long)elen, (long)elen + 1);
  911.  
  912.     /* flush changes */
  913. #if defined(HAVE_FSYNC) && !defined(O_SYNC)
  914.     (void) fsync(fd);
  915. #endif
  916.     }
  917. }
  918.  
  919. /*
  920.  * read_error - read an error description from a retry file
  921.  */
  922. static void
  923. read_error(fd, tryfile, error)
  924.     int fd;
  925.     char *tryfile;
  926.     struct error *error;
  927. {
  928.     struct stat statbuf;
  929.     char *buf, *errmsg, *p;
  930.     long errcode;
  931.     size_t len;
  932.  
  933.     /* assume that we can't read the file */
  934.     error->info = ERR_173;
  935.     error->message = "retry time expired";
  936.  
  937.     /* read the whole file */
  938.     if (fstat(fd, &statbuf) == -1 || statbuf.st_size > 0x7FFF) {
  939.     return;
  940.     }
  941.     len = (size_t)statbuf.st_size;
  942.     buf = xmalloc(len + 1);
  943.     if (read(fd, buf, len + 1) != len) {
  944.     xfree(buf);
  945.     return;
  946.     }
  947.     buf[len] = '\0';
  948.  
  949.     /* parse the error number and message */
  950.     errcode = 0;
  951.     errmsg = NULL;
  952.  
  953.     p = buf;
  954.     while (isdigit(*p)) {
  955.     ++p;
  956.     }
  957.     if (*p == ' ') {
  958.     *p++ = '\0';
  959.     errcode = atoi(buf);
  960.     errmsg = p;
  961.  
  962.     if (*errmsg) {
  963.         p = errmsg + strlen(errmsg) - 1;
  964.         if (*p == '\n') {
  965.         *p = '\0';
  966.         }
  967.     }
  968.     }
  969.  
  970.     /* if code and message are acceptable, use them */
  971.     if (errcode && errmsg && *errmsg) {
  972.     error->info = errcode;
  973.     error->message = COPY_STRING(errmsg);
  974.     }
  975.  
  976.     /* free copy of file */
  977.     xfree(buf);
  978. }
  979.  
  980. #else    /* O_CREAT && lock_fd_wait */
  981.  
  982. /*
  983.  * without three-parameter open and kernel locking,
  984.  * stub out all retry functions
  985.  */
  986.  
  987. char *
  988. read_retry_file()
  989. {
  990.     /* STUB */
  991.     return NULL;
  992. }
  993.  
  994. struct addr *
  995. retry_addr_before(in, defer, fail)
  996.     struct addr *in;
  997.     struct addr **defer;
  998.     struct addr **fail;
  999. {
  1000.     /* STUB */
  1001.     return in;
  1002. }
  1003.  
  1004. struct addr *
  1005. retry_addr_after(started, in, fail)
  1006.     time_t started;
  1007.     struct addr *in;
  1008.     struct addr **fail;
  1009. {
  1010.     /* STUB */
  1011.     return in;
  1012. }
  1013.  
  1014. void
  1015. retry_addr_finished(addr)
  1016.     struct addr *addr;
  1017. {
  1018.     /* STUB */
  1019. }
  1020.  
  1021. int
  1022. retry_host_lock(transport, host, defer_failure, error)
  1023.     struct transport *transport;
  1024.     char *host;
  1025.     int *defer_failure;
  1026.     struct error **error;
  1027. {
  1028.     /* STUB */
  1029.     return SUCCEED;
  1030. }
  1031.  
  1032. void
  1033. retry_host_unlock(started, error)
  1034.     time_t started;
  1035.     struct error *error;
  1036. {
  1037.     /* STUB */
  1038. }
  1039.  
  1040. #endif    /* O_CREAT && lock_fd_wait */
  1041.